home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Tools & Apps / OS⁄Toolbox / DialogBits ƒ / DialogBits.c next >
Encoding:
C/C++ Source or Header  |  1991-06-27  |  15.2 KB  |  372 lines  |  [TEXT/MPS ]

  1. /* DialogBits
  2. * providing a bunch of dialog manager snippets */
  3. /*************************************************************
  4. This sample shows how to deal with many of the most commonly asked Dialog Manager
  5. questions.  Dimming edit lines, using userItems, restricting edit lines to
  6. specific lengths, and some other stuff is included here.
  7. The programming style used here is designed to clearly show the specific
  8. actions I'm taking, _not_ to show good coding practice.  Obviously, you will 
  9. want to modify and optimize this code for your specific application.
  10. C.K. Haun
  11. Apple Developer Tech Support
  12. *************************************************************/
  13. #include <Dialogs.h>
  14. #include <Controls.h>
  15. #include <QuickDraw.h>
  16. #include <Windows.h>
  17. #include <ToolUtils.h>
  18. #include <OSUtils.h>
  19. #include <Menus.h>
  20. #include <Fonts.h>
  21. #include <resources.h>
  22.  
  23. /* item numbers */
  24. enum  {
  25.     kIconItem = 4, kBottomEditLine, kSpinItem, kTopEditLine, kEditCheckBox, kBorderBox, kDimmingBox = 10
  26. };
  27. /* this stuff would normally be in your .h file, but in this simple example */
  28. /* I just put them here */
  29. #define kSampleDialog 128
  30. #define kBaseSpinIcon 129
  31. #define kReturnKey 0x0D
  32. #define kEnterKey 0x03
  33. #define kEscKey 0x1B
  34. #define kTabKey 9
  35. enum  {
  36.     kBackSpace = 8, kLeftArrow = 0x1C, kRightArrow, kUpArrow, kDownArrow, kDeleteKey = 0x7F
  37. };
  38. /* prototypes */
  39. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem);
  40. void SpinIt(DialogPtr theDialog);
  41. pascal Boolean filterIt(DialogPtr dialer, EventRecord *myDialogEvent, short *theDialogItem);
  42. Boolean IsEditKey(theKey);
  43. void IBeamIt(WindowPtr dwind);
  44. pascal void BorderDefault(WindowPtr dwind, short dinum);
  45. pascal void DimEditLine(WindowPtr dwind, short dinum);
  46.  
  47. main()
  48. {
  49.     DialogPtr myDialog = nil;
  50.     short hitItem = 0;
  51.     Rect tempRect;
  52.     short tempItem;
  53.     Handle tempHandle;
  54.     Boolean tBool;
  55.     InitGraf((Ptr)&qd.thePort);
  56.     InitFonts();
  57.     InitWindows();
  58.     InitMenus();
  59.     TEInit();
  60.     InitDialogs(nil);
  61.     InitCursor();
  62.     myDialog = GetNewDialog(kSampleDialog, nil, (WindowPtr)-1);
  63.     /* set up our user items for various things */
  64.     GetDItem(myDialog, kBorderBox, &tempItem, &tempHandle, &tempRect);
  65.     SetDItem(myDialog, kBorderBox, tempItem, (Handle)BorderDefault, &tempRect);
  66.     GetDItem(myDialog, kDimmingBox, &tempItem, &tempHandle, &tempRect);
  67.     SetDItem(myDialog, kDimmingBox, tempItem, (Handle)DimEditLine, &tempRect);
  68.     
  69.     tempHandle = (Handle)SnatchHandle(myDialog, kEditCheckBox);
  70.     SetCtlValue((ControlHandle)tempHandle, false);
  71.     /* and since I want this edit line dimmed when the box first shows up, I'll */
  72.     /* select the other edit line */
  73.     SelIText((DialogPtr)myDialog, kTopEditLine, 0, 0);
  74.     ShowWindow((WindowPtr)myDialog);
  75.     DrawDialog(myDialog);
  76.     do {
  77.         ModalDialog((ModalFilterProcPtr)filterIt, &hitItem);
  78.         switch (hitItem) {
  79.             case kEditCheckBox:
  80.                 /* edit line dim checkbox */
  81.                 tempHandle = (Handle)SnatchHandle(myDialog, kEditCheckBox);
  82.                 tBool = GetCtlValue((ControlHandle)tempHandle);
  83.                 tBool ? tBool = false : tBool = true;
  84.                 SetCtlValue((ControlHandle)tempHandle, tBool);
  85.                 if (!tBool) {                               /* they turned the edit line off, we need to switch out of the EL if its */
  86.                     /* active */
  87.                     if (((DialogPeek)myDialog)->editField + 1 == kBottomEditLine)
  88.                         SelIText((DialogPtr)myDialog, kTopEditLine, 0, 0);
  89.                 }
  90.                 GetDItem(myDialog, kDimmingBox, &tempItem, &tempHandle, &tempRect);
  91.                 InvalRect(&tempRect);
  92.                 break;
  93.         }
  94.     } while (hitItem != 1 && hitItem != 2);
  95.     DisposDialog(myDialog);
  96. }
  97.  
  98. /* My dialog filter.  It's pretty crowded here, since I'm showing lots of */
  99. /* stuff.  You'd of course want it neatened up a bit */
  100. pascal Boolean filterIt(DialogPtr dialer, EventRecord *myDialogEvent, short *theDialogItem)
  101. {
  102.     WindowPtr temp;
  103.     char theKey;
  104.     Rect tempRect;
  105.     short tempItem;
  106.     Handle tempHandle;
  107.     long tilticks;
  108.     Boolean returnVal = false;
  109.     GetPort(&temp);
  110.     SetPort(dialer);
  111.     
  112.     /**********************************************************************/
  113.     /* Use something like this if you want to do any idle time drawing in your */
  114.     /* dialog, like a clock, flashing cursor, or a classy animated icon like I'm using */
  115.     /**********************************************************************/
  116.     SpinIt(dialer);
  117.     
  118.     /**********************************************************************
  119.     IBeamIt changes the cursor to an IBeam cursor when the cursor is over
  120.     the active edit line
  121.     **********************************************************************/
  122.     IBeamIt(dialer);
  123.     
  124.     /*************************************************************/
  125.     /* Some key filtering schemes follow.  The first is the standard filter to */
  126.     /* recognize 'return' as OK and 'ESC' as cancel.  What this really means */
  127.     /* is that I never ever want to have to use the mouse to click the cancel */
  128.     /* buttton ever again, you can just cut and paste this code from now on. */
  129.     /***********************************************************************/
  130.     /* do standard filtering for escape and return as OK and Cancel aliases */
  131.     /* We also invert the button in the dialog, so the user get's visual feedback */
  132.     /* about the action they just took */
  133.     if ((myDialogEvent->what == keyDown) || (myDialogEvent->what == autoKey)) {
  134.         theKey = myDialogEvent->message & charCodeMask;
  135.         switch (theKey) {
  136.             case kReturnKey:
  137.             case kEnterKey:                                 /* enter key */
  138.                 /* This filters for Return or Enter as item 1, and Esc as item 2 */
  139.                 *theDialogItem = 1;                         /* change whatever the current item is to the OK item */
  140.                 /* now we need to invert the button */
  141.                 HiliteControl(SnatchHandle(dialer, ok), inButton);
  142.                 Delay(8, &tilticks);                        /* wait about 8 ticks so they can see it */
  143.                 HiliteControl(SnatchHandle(dialer, ok), false);
  144.                 SetPort(temp);
  145.                 returnVal = true;
  146.                 break;
  147.                 /* This filters the escape key as the same as item 2 (the canx button, usually ) */
  148.             case kEscKey:
  149.                 *theDialogItem = 2;
  150.                 HiliteControl(SnatchHandle(dialer, cancel), inButton);
  151.                 Delay(8, &tilticks);                        /* wait about 8 ticks so they can see it */
  152.                 HiliteControl(SnatchHandle(dialer, cancel), false);
  153.                 SetPort(temp);
  154.                 returnVal = true;
  155.                 break;
  156.             case kTabKey:
  157.                 /* I'm filtering the tab key here so the user cannot tab to */
  158.                 /* my inactive edit line */
  159.                 if (!GetCtlValue((ControlHandle)SnatchHandle(dialer, kEditCheckBox)))
  160.                     returnVal = true;                       /* don't allow edit line swaps */
  161.                 break;
  162.         }
  163.     }
  164.     
  165.     /********************************************************************************/
  166.     /* Here's another kind of key filtering you need every so often, text or numeric */
  167.     /* filtering.  In this case, we're only going to allow non-numeric characters in */
  168.     /* the edit line we have installed in this dialog */
  169.     /* Any number will be eaten, and a beep generated */
  170.     /**************************************************/
  171.     if ((myDialogEvent->what == keyDown) || (myDialogEvent->what == autoKey)) {
  172.         theKey = myDialogEvent->message & charCodeMask;
  173.         
  174.         if ((theKey > 0x30 && theKey < 0x39) && ((DialogPeek)dialer)->editField + 1 == kBottomEditLine) {
  175.             /* Dang, it's a number and in the wrong edit line, reject it */
  176.             SysBeep(1);                                     /* complain a little */
  177.             returnVal = true;                               /* tell the dialog manager
  178.                                                             /* that we handled this already and */
  179.             /* it doesn't have to, so the keystroke will _not_ get */
  180.             /* added to the edit line */
  181.             
  182.         }
  183.     }
  184.     
  185.     /********************************************************************************/
  186.     /* Here's yet another kind of key filtering you need every so often.  */
  187.     /* I'm going to restrict the amount of text in the  edit line to just 25 characters */
  188.     /**************************************************/
  189.     
  190.     if (((myDialogEvent->what == keyDown) || (myDialogEvent->what == autoKey)) &&
  191.         ((DialogPeek)dialer)->editField + 1 == kTopEditLine) {
  192.         Str31 myStr;
  193.         GetDItem(dialer, kTopEditLine, &tempItem, &tempHandle, &tempRect);
  194.         GetIText(tempHandle, myStr);
  195.         if (myStr[0] > 25) {                                /* over 25, see what it is */
  196.             theKey = myDialogEvent->message & charCodeMask;
  197.             if (IsEditKey(theKey)) {
  198.                 returnVal = false;                          /* don't filter out editing keys */
  199.             } else {
  200.                 SysBeep(1);                                 /* complain a little */
  201.                 returnVal = true;                           /* tell the dialog manager that we handled this already and */
  202.                 /* it doesn't have to, so the keystroke will _not_ get */
  203.                 /* added to the edit line */
  204.                 
  205.             }
  206.         }
  207.     }
  208.     if (myDialogEvent->what == mouseDown) {
  209.         Point willy;
  210.         willy = (myDialogEvent->where);
  211.         GlobalToLocal(&willy);
  212.         GetDItem(dialer, kIconItem, &tempItem, &tempHandle, &tempRect);
  213.         if (PtInRect(willy, &tempRect)) {
  214.             Boolean hiLit = false;
  215.             Point tempPoint;
  216.             /* invert my icon, and track it whilst the user holds the mouse down */
  217.             InvertRect(&tempRect);
  218.             hiLit = true;
  219.             while (StillDown()) {
  220.                 GetMouse(&tempPoint);                       /* returns point in local coords */
  221.                 if (PtInRect(tempPoint, &tempRect)) {
  222.                     /* in the rect.  See if it's hilighted or not */
  223.                     if (!hiLit) {
  224.                         hiLit = true;
  225.                         InvertRect(&tempRect);
  226.                     }
  227.                 } else {
  228.                     /* not in the rectangle.  If it's hilit, get rid of that */
  229.                     if (hiLit) {
  230.                         hiLit = false;
  231.                         InvertRect(&tempRect);
  232.                     }
  233.                 }
  234.             }
  235.             if (hiLit) {
  236.                 /* if it's still hilited when the mouse comes up, then that means the */
  237.                 /* user stayed in and wants to take this icon action */
  238.                 InvertRect(&tempRect);                      /* clear the hiliting if it's still lit */
  239.                 *theDialogItem = kIconItem;
  240.                 returnVal = true;                           /* telling the Dialog Manager we handled it, pass item back */
  241.             }
  242.         } else {
  243.             /* first see if we even care about this click.  If the check box is true, then */
  244.             /* both edit lines are active, let the dialog manager handle it */
  245.             if (GetCtlValue(SnatchHandle(dialer, kEditCheckBox))) {
  246.                 returnVal = false;                          /* DM will handle */
  247.             } else {
  248.                 /* OK, so the edit line checkbox is NOT set, which means that we don't want */
  249.                 /* hits in the inactive edit line to do anything.  So, see if the hit was */
  250.                 /* in the edit line, and report 'true' if it was, telling the Dialog Manager that */
  251.                 /* you handled the event and it should do nothing */
  252.                 GetDItem(dialer, kBottomEditLine, &tempItem, &tempHandle, &tempRect);
  253.                 if (PtInRect(willy, &tempRect)) {
  254.                     returnVal = true;
  255.                 } else {
  256.                     returnVal = false;
  257.                 }
  258.             }
  259.         }
  260.     }
  261.     return(returnVal);
  262. }
  263.  
  264. void SpinIt(DialogPtr theDialog)
  265. {
  266.     static short pos;
  267.     static long count;
  268.     Handle myIcon;
  269.     Rect tempRect;
  270.     short tempItem;
  271.     Handle tempHandle;
  272.     
  273.     if (TickCount() > count + 10) {
  274.         count = TickCount();
  275.         myIcon = GetIcon(pos + kBaseSpinIcon);
  276.         /* you could have a rect in this function, but that'd require you to change it all 
  277.         * the time when you move the item around in your dialog.  So, we'll reference it 
  278.         * from the dialog record instead */
  279.         GetDItem(theDialog, kSpinItem, &tempItem, &tempHandle, &tempRect);
  280.         PlotIcon(&tempRect, myIcon);
  281.         ReleaseResource(myIcon);
  282.         pos++;
  283.         if (pos > 3)
  284.             pos = 0;
  285.     }
  286. }
  287.  
  288. /* BorderDefault draws a heavy border around the default button (in this case the OK button ) */
  289. pascal void BorderDefault(WindowPtr dwind, short dinum)
  290. {
  291. #pragma unused (dinum)
  292.     short itemtype;
  293.     Handle itemhandle;
  294.     Rect borderRect;
  295.     GetDItem(dwind, ok, &itemtype, &itemhandle, &borderRect);
  296.     /* ok is defined as 1 in the interfaces.  If you'd like another item outlined, */
  297.     /* change this number, of course. */
  298.     InsetRect(&borderRect, -4, -4);
  299.     PenSize(3, 3);
  300.     FrameRoundRect(&borderRect, 16, 16);
  301.     PenSize(1, 1);
  302. }
  303.  
  304. /* This userItem dims the bottom edit line if the check box is not checked */
  305. pascal void DimEditLine(WindowPtr dwind, short dinum)
  306. {
  307.     ControlHandle tempCont;
  308.     tempCont = SnatchHandle(dwind, kEditCheckBox);
  309.     if (GetCtlValue(tempCont)) {
  310.         /* the edit line should be active here, so don't overpaint */
  311.     } else {
  312.         PenState thePen;
  313.         short itemType;
  314.         Handle itemHandle;
  315.         Rect dimRect;
  316.         GetPenState(&thePen);
  317.         GetDItem(dwind, dinum, &itemType, &itemHandle, &dimRect);
  318.         PenMode(notPatBic);
  319.         PenPat(qd.gray);
  320.         PaintRect(&dimRect);
  321.         SetPenState(&thePen);
  322.         
  323.     }
  324. }
  325.  
  326. /* a little utility to see if the current key is an edit-type key */
  327. Boolean IsEditKey(theKey)
  328. {
  329.     register qq;
  330.     char editChars[5] =  {
  331.         kLeftArrow, kUpArrow, kRightArrow, kDownArrow, kBackSpace
  332.     };
  333.     for (qq = 0; qq < 6; qq++) {
  334.         if (theKey == editChars[qq])
  335.             return(true);
  336.     }
  337.     return(false);
  338. }
  339.  
  340. /* changes the cursor to an IBeam if it's over an active edit line, or to the */
  341. /* arrow if it's not */
  342. void IBeamIt(WindowPtr dwind)
  343. {
  344.     Point mouseAt;
  345.     short itemtype;
  346.     Handle itemhandle;
  347.     Rect borderRect;
  348.     short itemNum;
  349.     /* first get the current edit line out of the dialog record */
  350.     itemNum = ((DialogPeek)dwind)->editField + 1;           /* always stored 1 less */
  351.     GetDItem(dwind, itemNum, &itemtype, &itemhandle, &borderRect);
  352.     GetMouse(&mouseAt);
  353.     if (PtInRect(mouseAt, &borderRect)) {
  354.         SetCursor(*(GetCursor(1)));
  355.     } else {
  356.         InitCursor();
  357.         
  358.     }
  359. }
  360.  
  361. /* Gets the ControlHandle for the item you want in the dialog box thebox.  */
  362. /* Handy for setting checkboxes and radio buttons */
  363. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem)
  364. {
  365.     short itemtype;
  366.     Rect itemrect;
  367.     Handle thandle;
  368.     
  369.     GetDItem(thebox, theGetItem, &itemtype, &thandle, &itemrect);
  370.     return((ControlHandle)thandle);
  371. }
  372.